/*
 * Project it.battlehorse.rcp.tools.log
 * Created on Nov 19, 2005
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * A copy of the LGPL is available also at
 * http://www.gnu.org/copyleft/lesser.html
 * 
 */ 
package it.battlehorse.rcp.tools.log.internal;

import it.battlehorse.rcp.sl.annot.Injected;
import it.battlehorse.rcp.sl.annot.Serviceable;
import it.battlehorse.rcp.tools.commons.EventType;
import it.battlehorse.rcp.tools.commons.Severity;
import it.battlehorse.rcp.tools.log.BasicLoggable;
import it.battlehorse.rcp.tools.log.ILoggable;
import it.battlehorse.rcp.tools.log.LogActivator;
import it.battlehorse.rcp.tools.log.LogCollector;
import it.battlehorse.rcp.tools.log.views.ActorLogView;

import org.apache.commons.logging.Log;
import org.eclipse.jface.util.IPropertyChangeListener;

/**
 * An implementation of {@code org.apache.commons.logging.Log } which redirects
 * the logging requests to the dedicated view ({@link ActorLogView}).
 * 
 * @author battlehorse
 * @since Nov 19, 2005
 */
@Serviceable
public class Logger implements Log, IPropertyChangeListener {
	
	private String className;
	
	/* These boolean values define the current logging level */
	private boolean isTraceEnabled, isInfoEnabled, isWarningEnabled, isErrorEnabled;
	
	/* An instance of the log collector */
	private LogCollector collector;
	
	/**
	 * Injects the log collector into this object
	 * 
	 * @param collector the log collector
	 */
	@Injected
	public void setLogCollector(LogCollector collector) {
		this.collector = collector;
	}
	
	/**
	 * Creates a new instance of the class
	 * 
	 * @param className
	 */
	public Logger(String className) {
		this.className = className;
		
		//
		// Sets the logging level, extracting it from the current preferences
		//
		String level = LogActivator.getDefault().getPreferenceStore().getString("LogPreferences.LogLevel");
		setLogLevel(level);
		
		// Register with the PreferencesStore to be notified whenever the log
		// level changes
		LogActivator.getDefault().getPreferenceStore().addPropertyChangeListener(this);
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isDebugEnabled()
	 */
	public boolean isDebugEnabled() {
		return isTraceEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isErrorEnabled()
	 */
	public boolean isErrorEnabled() {
		return isErrorEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isFatalEnabled()
	 */
	public boolean isFatalEnabled() {
		return isErrorEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isInfoEnabled()
	 */
	public boolean isInfoEnabled() {
		return isInfoEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isTraceEnabled()
	 */
	public boolean isTraceEnabled() {
		return isTraceEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#isWarnEnabled()
	 */
	public boolean isWarnEnabled() {
		return isWarningEnabled;
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object)
	 */
	public void trace(Object arg0) {
		trace(arg0,null);
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object, java.lang.Throwable)
	 */
	public void trace(Object arg0, Throwable arg1) {
		if (isTraceEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.TRACE;				
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#debug(java.lang.Object)
	 */
	public void debug(Object arg0) {
		debug(arg0,null);
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#debug(java.lang.Object, java.lang.Throwable)
	 */
	public void debug(Object arg0, Throwable arg1) {
		if (isDebugEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.TRACE;
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#info(java.lang.Object)
	 */
	public void info(Object arg0) {
		info(arg0,null);

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#info(java.lang.Object, java.lang.Throwable)
	 */
	public void info(Object arg0, Throwable arg1) {
		if (isInfoEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.INFO;
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#warn(java.lang.Object)
	 */
	public void warn(Object arg0) {
		warn(arg0,null);

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#warn(java.lang.Object, java.lang.Throwable)
	 */
	public void warn(Object arg0, Throwable arg1) {
		if (isWarnEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.WARNING;
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#error(java.lang.Object)
	 */
	public void error(Object arg0) {
		error(arg0,null);

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#error(java.lang.Object, java.lang.Throwable)
	 */
	public void error(Object arg0, Throwable arg1) {
		if (isErrorEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.ERROR;
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object)
	 */
	public void fatal(Object arg0) {
		fatal(arg0,null);
	}

	/* (non-Javadoc)
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object, java.lang.Throwable)
	 */
	public void fatal(Object arg0, Throwable arg1) {
		if (isFatalEnabled()) {
			ILoggable loggable = null;
			if (!(arg0 instanceof ILoggable)) {
				BasicLoggable l = getLoggable(arg0,arg1);			
				l.severity = Severity.ERROR;
				loggable = l;
			}
			else
				loggable = (ILoggable) arg0;
			
			collector.notifyLogListeners(loggable);
		}

	}
	
	/**
	 * Converts the given message into an {@code ILoggable } element. 
	 * 
	 * @param message the message to be logged
	 * @return an equivalent {@code ILoggable } object
	 */
	private BasicLoggable getLoggable(Object message) {
				
		BasicLoggable loggable = new BasicLoggable(
				message == null ? "null" : message.toString(),
				className);
		loggable.type = EventType.GENERIC_EVENT;
		
		return loggable;
	}
	
	/**
	 * Converts the given message into an {@code ILoggable } element. 
	 * 
	 * @param message the message to be logged
	 * @param t a Throwable associated to the log message
	 * @return an equivalent {@code ILoggable } object
	 */
	private BasicLoggable getLoggable(Object message, Throwable t) {	
		
		if (t == null)
			return getLoggable(message);
		else {
			BasicLoggable loggable = new BasicLoggable(
					t.getMessage() == null ? t.getClass().getName() : t.getMessage(),
					t,
					className);
			loggable.type = EventType.EXCEPTION_EVENT;
			
			return loggable;
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
	 */
	public void propertyChange(org.eclipse.jface.util.PropertyChangeEvent event) {
		
		if ("LogPreferences.LogLevel".equals(event.getProperty())) {
			//
			// The logging level has changed
			//
			String newLevel = event.getNewValue().toString();
			setLogLevel(newLevel);
		}
		
	}
	
	/**
	 * Sets the new logging level
	 * 
	 * @param newLevel the new logging level
	 */
	private void setLogLevel(String newLevel) {
		if (newLevel.equals(Severity.TRACE.getMessage())) {
			isTraceEnabled = true;
			isInfoEnabled = true;
			isWarningEnabled = true;
			isErrorEnabled = true;			
		}
		else if (newLevel.equals(Severity.INFO.getMessage())) {
			isTraceEnabled = false;
			isInfoEnabled = true;
			isWarningEnabled = true;
			isErrorEnabled = true;						
		}
		else if (newLevel.equals(Severity.WARNING.getMessage())) {
			isTraceEnabled = false;
			isInfoEnabled = false;
			isWarningEnabled = true;
			isErrorEnabled = true;					
		}
		else if (newLevel.equals(Severity.ERROR.getMessage())) {
			isTraceEnabled = false;
			isInfoEnabled = false;
			isWarningEnabled = false;
			isErrorEnabled = true;						
		}
	}

}
